//! 默认情况下，任何特权级别的 trap 都会在 machine mode 下处理，但也
//! 可以借助 MRET 指令将 trap 重定向到合适的级别中处理。
//!
//! 为了提供性能，具体实现可以通过 medeleg(mideleg) 将特定的异常或中断委托给更低的特权级别。
//!
//! 如果系统实现了 S-mode，则 medeleg 和 mideleg 必须存在。
//! 设置 medeleg 和 mideleg 中相应的 bit 位，则会将相应的 trap（S-mode 或 U-mode） 委托给 S-mode 的 trap handler。
//!
//! ⚠️ 如果没有实现 S-mode，则不应当存在 medeleg 和 mideleg 寄存器。

use bits::{BitsOps, IntoBits};

use crate::{csrr, csrw, exception::Exception};

pub fn read() -> usize {
    csrr!(medeleg)
}

pub fn write(value: usize) {
    csrw!(medeleg, value)
}

pub fn cache() -> Cache {
    Cache { raw: read() }
}

pub struct Cache {
    raw: usize,
}
impl Cache {
    /// 注意并不是所有的 Exception 都是可以委托的。
    /// 由于 medeleg 寄存器是 WARL，所以函数内并不做合法性判断。
    pub fn deleg(&mut self, exception: Exception) -> &mut Self {
        let idx: usize = exception.into();
        self.raw = self.raw.bits(idx as u32).set();
        self
    }
    pub fn undeleg(&mut self, exception: Exception) -> &mut Self {
        let idx: usize = exception.into();
        self.raw = self.raw.bits(idx as u32).clr();
        self
    }
    pub fn flush(self) {
        write(self.raw)
    }
}
